
打鐵趁熱,整理了一部分最近開發上學到的事情,希望讀者不吝予以指教!
本文將介紹並深入比較兩種主要的 PostgreSQL 資料庫連線管理方式,在開發網站或應用程式時,如何有效管理資料庫連線是一個重要的課題,想像資料庫就像是應用程式的資料中心,我們需要建立連線才能存取這些資料,而連線的管理方式,就會直接影響到應用程式的效能、穩定性和資源使用效率。
主要由三個核心組件組成,讓我們逐一了解他們的功能和特點。
這是整個架構的基礎層,負責管理資料庫連線池的核心功能:
from psycopg2 import pool
class DatabaseConfig:
    _connection_pool = None
    
    @classmethod
    def initialize(cls, minconn=1, maxconn=10):
        """初始化資料庫連線池"""
        if cls._connection_pool is None:
            cls._connection_pool = pool.ThreadedConnectionPool(
                minconn,
                maxconn,
                host="localhost",
                database="mydb",
                user="user",
                password="password"
            )
    
    @classmethod
    def get_connection(cls):
        """從連線池獲取連線"""
        return cls._connection_pool.getconn()
    
    @classmethod
    def return_connection(cls, conn):
        """將連線歸還給連線池"""
        cls._connection_pool.putconn(conn)
    
    @classmethod
    def close_all(cls):
        """關閉所有連線"""
        if cls._connection_pool:
            cls._connection_pool.closeall()
這是中間層,主要負責連線的生命週期管理:
from contextlib import contextmanager
import logging
@contextmanager
def get_db_connection():
    conn = None
    try:
        conn = DatabaseConfig.get_connection()
        yield conn
        conn.commit()
    except Exception as e:
        if conn:
            conn.rollback()
            logging.error(f"Database error: {str(e)}")
        raise
    finally:
        if conn:
            DatabaseConfig.return_connection(conn)
這是最上層,負責將連線池與應用程式整合:
from fastapi import FastAPI
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: FastAPI):
    # 應用啟動時初始化
    logging.info("Initializing database connection pool")
    DatabaseConfig.initialize(minconn=5, maxconn=20)
    
    yield
    
    # 應用關閉時清理
    logging.info("Closing database connections")
    DatabaseConfig.close_all()
app = FastAPI(lifespan=lifespan)
def get_user(user_id):
    with get_db_connection() as conn:
        with conn.cursor() as cur:
            cur.execute("SELECT * FROM users WHERE id = %s", (user_id,))
            return cur.fetchone()
資源管理
自動化處理
進階選項
簡單粗暴,適合剛學習資料庫應用的方法。
from fastapi import Depends
import asyncpg
async def get_database_connection():
    conn = await asyncpg.connect(
        host="localhost",
        database="mydb",
        user="user",
        password="password"
    )
    return conn
@app.get("/users/{user_id}")
async def get_user(
    user_id: int, 
    conn: asyncpg.Connection = Depends(get_database_connection)
):
    row = await conn.fetchrow("SELECT * FROM users WHERE id = $1", user_id)
    return row
為了讓非技術背景的讀者更容易理解這些概念,我用點餐流程來比喻請求與資料庫之間的關係,想像一下當你走進一間麥當勞:
有 1-5 個櫃檯:
特點:
沒有櫃檯,客人直接進廚房找餐點:
特點:
選擇合適的連線管理方式需要考慮多個因素:
對於大多數生產環境的應用來說,使用連線池管理是更好的選擇,它提供了更好的性能和資源管理能力,就像麥當勞不可能讓所有客人直接進廚房一樣,資料庫存取也需要有序且受控的管理機制。反之,對於開發環境或簡單應用,建立單一連線在需要快速迭代的開發測試需求上可能更有優勢。